#include "drm.hpp"

void ManDRM::drmBuffSwap(){
	int ret = 0;
	ret = drmModeSetPlane(m_fd, m_plane_id, m_crtc_id,m_buf[m_index].fb_id, 0, 0, 0, m_buf[m_index].width,m_buf[m_index].height, 0, 0, m_buf[m_index].width << 16, m_buf[m_index].height << 16);
	if(ret < 0){
		cout << "Swap drmModeSetPlane err" << endl;
		return;
	}
}

ManDRM::buffer_object * ManDRM::getBufSwap(){
	if(m_index == 0)
		m_index = 1;
	else
		m_index = 0;
	return &m_buf[m_index];
}

void ManDRM::printDRMInfo(){
	int fd = m_fd;
	drmModePlaneRes *pr = m_plane_res;
	
	drmModeObjectPropertiesPtr props;
	int i,j;
	drmModePropertyPtr p;
	cout << "=============================" << endl; 
	cout << "Info" << endl; 
	cout << "=============================" << endl; 
	cout << "Plane ID: " << m_plane_id << endl; 
	cout << "Crtc ID: " << m_crtc_id << endl; 
	cout << "Connector ID: " << m_conn_id << endl; 
	cout << "=============================" << endl; 
/*	
	cout << "Plane" << endl; 
	cout << "=============================" << endl; 
	for(i = 0; i < pr->count_planes; i++) {
		
		if(i == 0)
			cout << "(Main): ";
		if(pr->planes[i] == m_plane_id)
			cout << "(Cur plane): ";
		cout << "Planes id: " << pr->planes[i] << endl;
		props = drmModeObjectGetProperties(fd, pr->planes[i],
				DRM_MODE_OBJECT_PLANE);
					
		for (j = 0;j < props->count_props; j++) {
			p = drmModeGetProperty(fd, props->props[j]);
			cout << string("Get property ,Name: ") + p->name + ", ID: " << p->prop_id << endl;
			drmModeFreeProperty(p);
		}	
	}
*/
	
}

void ManDRM::_modeSetDestroyFB(int fd, struct buffer_object *bo)
{
	for(int i = 0; i < 2; i++) {
		struct drm_mode_destroy_dumb destroy = {};

		drmModeRmFB(fd, bo[i].fb_id);

		munmap(bo->vaddr, bo[i].size);
		if(bo[i].fd > 0)
			close(bo[i].fd);

		destroy.handle = bo[i].handle;
		drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
	}
}

void ManDRM::_writeColor(struct buffer_object *bo,unsigned int color)
{
	for(int i = 0; i < 2; i++) {
		unsigned int *pt;
		int j;

		pt = (unsigned int *)bo[i].vaddr;
		for (j = 0; j < (bo[i].size / 4); j++){
			*pt = color;
			pt++;
		}
	}	
	
}

int ManDRM::_modeSetCreateFB(int fd, struct buffer_object *bo)
{
	for(int i = 0; i < 2; i++) {
		struct drm_mode_create_dumb create = {};
		struct drm_mode_map_dumb map = {};
		uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
		int ret;


		create.width = bo[i].width;
		create.height = bo[i].height;
		create.bpp = 32;
		drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);

		bo[i].pitch = create.pitch;
		bo[i].size = create.size;
		bo[i].handle = create.handle;

		map.handle = create.handle;
		drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);

		bo[i].vaddr = (unsigned char *)mmap(0, create.size, PROT_READ | PROT_WRITE,
				MAP_SHARED, fd, map.offset);

#if 0
		drmModeAddFB(fd, bo[i].width, bo[i].height, 24, 32, bo[i].pitch,
				bo[i].handle, &bo[i].fb_id);
#else
		offsets[0] = 0;
		handles[0] = bo[i].handle;
		pitches[0] = bo[i].pitch;

		ret = drmModeAddFB2(fd, bo[i].width, bo[i].height,
				DRM_FORMAT_XRGB8888, handles, pitches, offsets,&bo[i].fb_id, 0);
		if(ret ){
			cout << "drmModeAddFB2 return err" << endl;
			return 0;
		}


#endif

		ret = drmPrimeHandleToFD(fd, bo[i].handle, DRM_CLOEXEC | DRM_RDWR, &bo[i].fd);
		if(ret < 0)
			return -1;
		memset(bo[i].vaddr, 0xff, bo[i].size);
	}
	return 0;
}


ManDRM::ManDRM(){
	
	int ret = 0;
	m_fd = open(DRM_CARD_NAME, O_RDWR | O_CLOEXEC);
	if(m_fd < 0){
		cout << string("Open ") + DRM_CARD_NAME + " err" << endl;
		return;
	}
	m_res = drmModeGetResources(m_fd);
	m_crtc_id = m_res->crtcs[0];
	m_conn_id = m_res->connectors[0];

	/* 
	   不调用 DRM_CLIENT_CAP_UNIVERSAL_PLANES 获取到的 plane 资源就只有 overlay 层，
	   调用之后获取的是所有图层资源。
	*/
	ret = drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
	if (ret) {
		cout << "Set DRM_CLIENT_CAP_UNIVERSAL_PLANES err" << endl;
		return;
	}

	m_plane_res = drmModeGetPlaneResources(m_fd); //获取 plane 资源
	m_plane_id = m_plane_res->planes[1]; //获取数组的一个元素的 plane id ,通常就是 vp0 的主图层。通过 cat /sys/kernel/debug/dri/0/state |grep "plane\[" 查看
	
	m_conn = drmModeGetConnector(m_fd, m_conn_id); // 获取对应 connector id 资源
	m_buf[0].width = m_conn->modes[0].hdisplay;
	m_buf[0].height = m_conn->modes[0].vdisplay;

	m_buf[1].width = m_buf[0].width;
	m_buf[1].height = m_buf[0].height;

	_modeSetCreateFB(m_fd, m_buf); // 创建一块 DRM buff 用于显示，以后刷新就通过更新这块 buff
	_writeColor(m_buf,0x00000000); // 初始化这块 buf 为黑色
	
	ret = drmModeSetPlane(m_fd, m_plane_id, m_crtc_id,m_buf[0].fb_id, 0, 0, 0, m_buf[0].width,m_buf[0].height, 0, 0, m_buf[0].width << 16, m_buf[0].height << 16);
	if(ret < 0){
		cout << "First drmModeSetPlane err" << endl;
		return;
	}

	m_index = 0;
	
}

ManDRM::~ManDRM(){
	_modeSetDestroyFB(m_fd, m_buf);

	drmModeFreeConnector(m_conn);
	drmModeFreePlaneResources(m_plane_res);
	drmModeFreeResources(m_res);

	close(m_fd);
}

